package com.zzyl.intercept;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zzyl.constant.CacheConstants;
import com.zzyl.constant.Constants;
import com.zzyl.properties.JwtTokenProperties;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.MgtThreadLocal;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

@Component
public class ManagerLoginInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtTokenProperties jwtTokenProperties;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    /**
     * 前置拦截 : 在控制层方法执行之前进行拦截
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1. 获取请求头中token
        String token = request.getHeader(Constants.USER_TOKEN);
        //2. 判断token是否存在
        if (StrUtil.isEmpty(token)){
            //2.1 如果token不存在 , 返回401
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        //3. 如果token存在, 校验token
        Claims claims = JwtUtil.parseJWT(jwtTokenProperties.getSecretKey(), token);
        //3.1 校验失败 , 返回401
        //4. 解析token获取token中的用户信息
        //Long userId = claims.get(Constants.JWT_USERID, Long.class);
        String userInfo_json = claims.get(Constants.JWT_USERINFO, String.class);
        JSONObject jsonObject = JSONUtil.parseObj(userInfo_json);
        Long userId = jsonObject.getLong("id");
        //5. 根据用户id获取redis中的可访问权限列表
        String json = redisTemplate.opsForValue().get(CacheConstants.ACCESS_URLS + userId);
        if (StrUtil.isEmpty(json)){
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return false;
        }
        List<String> accessList = JSONUtil.toList(json, String.class);
        //6. 判断当前请求路径是否在可访问权限列表中(数据库的路径配置方式 : 请求方式+请求路径)
        String path = request.getMethod()+request.getRequestURI();
        // anyMatch() : 匹配流中的任意一个元素返回 true , 全部都不匹配返回false
        boolean anyMatch = accessList.stream().anyMatch(access -> antPathMatcher.match(access, path));
        if (!anyMatch){
            //6.1 如果没有在可访问权限列表中, 返回403
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            return false;
        }
        //7. 校验通过 保存用户信息到ThreadLocal , 放行
        MgtThreadLocal.set(userInfo_json);

        return true;
    }

    /**
     * 后置拦截 : 在控制层方法执行之后进行拦截(释放线程中的数据)
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 清理线程数据, 防止内存泄漏
        MgtThreadLocal.remove();
    }
}
